<template>
  <div ref="chartContainer" class="doughnut-chart-container pos-relative"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as d3 from "d3";

interface PieData {
  label: string;
  value: number;
  color: string;
}
interface PieArcDatum extends d3.DefaultArcObject {
  data: PieData;
  innerRadius: number; // 明确声明
  outerRadius: number; // 明确声明
  padAngle?: number; // 可选属性
}

// 常量定义
const DEFAULT_HEIGHT = 200;
const DEFAULT_INNER_RADIUS_RATIO = 0.6;
const HOVER_SCALE_FACTOR = 1.25;
const ANIMATION_DURATION = 1000;
const TOOLTIP_OFFSET = { x: 15, y: -28 };

const props = defineProps<{
  data: PieData[];
  isNightingale: boolean;
  showGuideLine: boolean;
  innerRadiusRatio: number;
  theme?: string;
  highlightColor?: string;
  margin: {
    top: number;
    right: number;
    bottom: number;
    left: number;
  };
}>();

const chartContainer = ref<HTMLElement>();
const width = ref(0);
const height = ref(0);
const offsetX = ref<number>(0);
const offsetY = ref<number>(0);
const chartData: PieData[] = [
  { label: "产品A", value: 35, color: "#4e79a7" },
  { label: "产品B", value: 25, color: "#f28e2b" },
  { label: "产品C", value: 20, color: "#e15759" },
  { label: "产品D", value: 15, color: "#76b7b2" },
  { label: "产品E", value: 5, color: "#59a14f" },
];

let resizeObserver: ResizeObserver;

onMounted(() => {
  initDimensions();
  initChart();
  initResizeObserver();
});

onBeforeUnmount(() => {
  resizeObserver?.disconnect();
});
// 初始化尺寸
const initDimensions = () => {
  if (!chartContainer.value) return;

  width.value = chartContainer.value.clientWidth;
  height.value = chartContainer.value.clientHeight || DEFAULT_HEIGHT;
  const rect = chartContainer.value.getBoundingClientRect();
  offsetX.value = rect.left;
  offsetY.value = rect.top;
};
const initResizeObserver = () => {
  if (!chartContainer.value) return;
  resizeObserver = new ResizeObserver(() => {
    initDimensions();
    initChart();
  });
  resizeObserver.observe(chartContainer.value);
};

const initChart = () => {
  if (!chartContainer.value) return;

  // 清除旧图表
  d3.select(chartContainer.value).selectAll("*").remove();

  const radius = Math.min(width.value, height.value) / 3;
  const innerRadius = radius * props.innerRadiusRatio; // 关键参数：控制空心部分大小

  // 创建SVG容器
  const svg = d3
    .select(chartContainer.value)
    .append("svg")
    .attr("width", width.value)
    .attr("height", height.value)
    .append("g")
    .attr("transform", `translate(${width.value / 2},${height.value / 2})`);
  // 创建工具提示
  const tooltip = createToolbar();
  // 创建饼图生成器
  const pie = d3
    .pie<PieData>()
    .value((d) => d.value)
    .sort(null);

  // 创建弧生成器（关键区别：设置innerRadius）
  const arc = d3
    .arc<PieArcDatum>()
    .innerRadius(innerRadius) // 环形图核心配置
    .outerRadius(radius);

  // 绘制环形
  const arcs = svg
    .selectAll(".arc")
    .data(pie(chartData))
    .enter()
    .append("g")
    .attr("transform", (_d, _i) => `translate(0,-20)`) // 调整位置
    .attr("class", "arc");

  // 创建路径并保存引用
  const arcsPaths = arcs
    .append("path")
    .attr("class", "sector-path") // 添加class便于选择
    .attr("fill", (d) => d.data.color)
    .attr("stroke", "#fff")
    .attr("stroke-width", 0);

  // 添加扇形路径（带动画）
  arcsPaths
    .attr("transform", (d) => {
      if (!props.isNightingale) {
        return `scale(1)`;
      } else {
        const maxValue = d3.max(chartData, (d) => d.value) || 1;
        const scaleRatio = 0.8 + (d.value / maxValue) * 0.4; // 缩放范围 0.8~1.2
        return `scale(${scaleRatio})`;
      }
    })
    .transition()
    .duration(1000)
    .attrTween("d", function (d) {
      // 创建符合 DefaultArcObject 的起始状态
      const start: PieArcDatum = {
        startAngle: 0,
        endAngle: 0,
        innerRadius: innerRadius, // 必须包含
        outerRadius: radius, // 必须包含
        padAngle: 0,
        data: d.data,
      };

      // 安全类型转换
      const target: PieArcDatum = {
        ...d,
        innerRadius: innerRadius,
        outerRadius: radius,
      };

      const interpolate = d3.interpolate(start, target);
      return (t) => arc(interpolate(t))!;
    });
  // 添加扇形悬停效果
  renderInteractions(arcs, tooltip);

  // --添加引导线提示信息
  if (props.showGuideLine) {
    renderLineTooltip(arcs, tooltip, radius, innerRadius, width.value, height.value);
  }
  // --添加标题
  renderChartTitle(pie, svg, arcsPaths, width.value, height.value);
};
// --绘制标题
const renderChartTitle = (
  pie: any,
  svg: any,
  _arcsPaths: any,
  width: number,
  height: number
) => {
  console.log(width, height);
  // 在绘制环形图的代码后添加标题组
  const labels = svg.append("g").attr("class", "chart-labels");

  // 为每个产品添加标题
  labels
    .selectAll(".product-title")
    .data(pie(chartData))
    .enter()
    .append("g")
    .attr("class", "title-group")
    .style("cursor", "pointer")
    .attr("transform", (_d: any, i: any) => `translate(${-130 + i * 60}, 80)`) // 调整位置
    .each(function (this: HTMLElement, d: any) {
      const group = d3.select(this);

      // 添加色块
      group
        .append("rect")
        .attr("x", -15)
        .attr("y", -5)
        .attr("width", 12)
        .attr("height", 12)
        .attr("rx", 2) // 圆角
        .attr("ry", 2)
        .attr("fill", d.data.color);

      // 添加文本
      group
        .append("text")
        .attr("x", 0)
        .attr("y", 0)
        .attr("dy", "0.35em")
        .text(d.data.label)
        .style("font-size", "14px")
        .style("fill", props.theme == "dark" ? "#000" : "#fff");
    });
  // 修改交互代码
  labels
    .selectAll(".title-group")
    .on("mouseover", function (_event: any, d: any) {
      // 使用class选择器确保选择正确的元素
      svg
        .selectAll(".sector-path")
        .filter((p: any) => p.data.label === d.data.label)
        .transition()
        .attr("transform", (p: any) => {
          if (!props.isNightingale) return "scale(1.1)";
          const maxValue = d3.max(chartData, (x) => x.value) || 1;
          const baseScale = 0.8 + (p.data.value / maxValue) * 0.4;
          return `scale(${baseScale * 1.25})`;
        });
    })
    .on("mouseout", function (_event: any, d: any) {
      svg
        .selectAll(".sector-path")
        .filter((p: any) => p.data.label === d.data.label)
        .transition()
        .attr("transform", (p: any) => {
          if (!props.isNightingale) return "scale(1)";
          const maxValue = d3.max(chartData, (x) => x.value) || 1;
          return `scale(${0.8 + (p.data.value / maxValue) * 0.4})`;
        });
    });
  // 添加中心标题文字（可选）
  svg
    .append("text")
    .attr("x", -width / 2 + 40)
    .attr("y", -100)
    .attr("text-anchor", "middle")
    .attr("dy", "0.35em")
    .style("font-size", "12px")
    .style("font-weight", "bold")
    .style("fill", "#ccc")
    .text("销售占比");
};
// --创建工具条
const createToolbar = () => {
  if (!chartContainer.value) throw new Error("Chart container not found");
  // 创建工具提示
  return d3
    .select(chartContainer.value)
    .append("div")
    .attr("class", "doughnut-tooltip")
    .style("opacity", 0)
    .style("position", "absolute")
    .style("background", "rgba(0,0,0,0.35)")
    .style("color", "white")
    .style("padding", "8px 12px")
    .style("border-radius", "4px")
    .style("pointer-events", "none");
};
// --添加扇形悬停效果
const renderInteractions = (arcs: any, tooltip: any) => {
  arcs
    .select("path")
    .on("mouseover", function (this: SVGRectElement, event: any, d: any) {
      // 获取当前 transform 属性
      const currentTransform = d3.select(this).attr("transform") || "scale(1)";
      // 解析当前 scale 值（正则匹配）
      const scaleMatch = currentTransform.match(/scale\(([0-9.]+)\)/);
      const currentScale = scaleMatch ? parseFloat(scaleMatch[1]) : 1;

      // 计算新的 scale（当前 scale * 1.5）
      const newScale = currentScale * 1.25;
      // 当前扇形高亮
      d3.select(this)
        .transition()
        .duration(200)
        .attr("stroke-width", 0)
        .attr("opacity", 0.9)
        .attr("cursor", "pointer")
        .attr("transform", `scale(${newScale})`); // 放大效果

      // 显示工具提示
      // 先更新内容和位置
      tooltip
        .html(`<div>${d.data.label}: ${d.data.value}</div>`)
        .style("left", `${event.pageX - offsetX.value + 15}px`)
        .style("top", `${event.pageY - offsetY.value - 28}px`);

      // 最后执行动画
      tooltip.transition().duration(200).style("opacity", 1);
    })
    .on("mouseout", function (this: SVGRectElement) {
      // 恢复原始状态
      d3.select(this)
        .transition()
        .duration(300)
        .attr("stroke-width", 0)
        .attr("opacity", 1)
        .attr("transform", (d: any) => {
          if (!props.isNightingale) {
            return `scale(1)`;
          } else {
            const maxValue = d3.max(chartData, (d) => d.value) || 1;
            const scaleRatio = 0.8 + (d.value / maxValue) * 0.4; // 缩放范围 0.8~1.2
            return `scale(${scaleRatio})`;
          }
        });

      // 隐藏工具提示
      tooltip.transition().duration(300).style("opacity", 0);
    });
};
// --添加引导线提示信息
const renderLineTooltip = (
  arcs: any,
  tooltip: any,
  radius: number,
  innerRadius: number,
  width: number,
  height: number
) => {
  // 创建标签组
  const labels = arcs
    .append("g")
    .attr("class", "arc-label")
    .attr("text-anchor", "middle")
    .style("pointer-events", "none");

  // 添加引导线
  labels
    .append("path")
    .attr("class", "label-line")
    .attr("stroke", "#999")
    .attr("stroke-width", 1)
    .attr("fill", "none");

  // 添加文本标签
  labels
    .append("text")
    .attr("class", "label-text")
    .style("font-size", "12px")
    .style("fill", props.theme === "dark" ? "#000" : "#fff");

  // 更新标签位置
  updateLabelPositions(arcs, radius, innerRadius, width, height);

  // 添加标签悬停效果
  labels
    .on("mouseover", function (this: SVGGElement, event: MouseEvent, d: any) {
      d3.select(this).select(".label-text").style("font-weight", "bold");
      tooltip
        .html(`<div>${d.data.label}: ${d.data.value}</div>`)
        .style("left", `${event.pageX + 15}px`)
        .style("top", `${event.pageY - 28}px`)
        .transition()
        .duration(200)
        .style("opacity", 1);
    })
    .on("mouseout", function (this: SVGGElement) {
      d3.select(this).select(".label-text").style("font-weight", "normal");
      tooltip.transition().duration(200).style("opacity", 0);
    });
};
// 更新标签位置函数
const updateLabelPositions = (
  arcs: any,
  radius: number,
  innerRadius: number,
  width: number,
  height: number
) => {
  const arc = d3.arc<PieArcDatum>().innerRadius(innerRadius).outerRadius(radius);

  arcs.select(".label-line").attr("d", (d: any) => {
    const centroid = arc.centroid(d);
    const midAngle = Math.atan2(centroid[1], centroid[0]);

    // 1. 计算扇形边缘点
    const edgePoint = [Math.cos(midAngle) * radius, Math.sin(midAngle) * radius];

    // 2. 计算第一段倾斜线的终点（向外延伸）
    const bendDistance = 15;
    const bendPoint = [
      edgePoint[0] + Math.cos(midAngle) * bendDistance,
      edgePoint[1] + Math.sin(midAngle) * bendDistance,
    ];

    // 3. 计算水平线终点（根据象限决定方向）
    const horizontalLength = 20;
    let horizontalDirection = 1; // 默认为向右

    // 修正角度判断逻辑（使用标准数学坐标系）
    if (midAngle > Math.PI / 2 || midAngle < -Math.PI / 2) {
      horizontalDirection = -1; // 左半圆向左延伸
    }

    const labelPoint = [
      bendPoint[0] + horizontalLength * horizontalDirection,
      bendPoint[1], // 保持y坐标不变
    ];

    // 4. 界壁检测和调整（保持不变）
    const padding = 10;
    const labelWidth = d.data.label.length * 7;

    if (labelPoint[0] + labelWidth / 2 > width / 2 - padding) {
      labelPoint[0] = width / 2 - padding - labelWidth / 2;
    } else if (labelPoint[0] - labelWidth / 2 < -width / 2 + padding) {
      labelPoint[0] = -width / 2 + padding + labelWidth / 2;
    }
    if (labelPoint[1] > height / 2 - padding) {
      labelPoint[1] = height / 2 - padding;
    }

    return `
      M${centroid[0]},${centroid[1]}
      L${edgePoint[0]},${edgePoint[1]}
      L${bendPoint[0]},${bendPoint[1]}
      L${labelPoint[0]},${labelPoint[1]}
    `;
  });

  arcs
    .select(".label-text")
    .attr("transform", (d: any) => {
      // 使用与引导线相同的计算逻辑
      const centroid = arc.centroid(d);
      const midAngle = Math.atan2(centroid[1], centroid[0]);
      const edgePoint = [Math.cos(midAngle) * radius, Math.sin(midAngle) * radius];
      const bendDistance = 15;
      const bendPoint = [
        edgePoint[0] + Math.cos(midAngle) * bendDistance,
        edgePoint[1] + Math.sin(midAngle) * bendDistance,
      ];

      // 同样的方向判断逻辑
      let horizontalDirection = 1;
      if (midAngle > Math.PI / 2 || midAngle < -Math.PI / 2) {
        horizontalDirection = -1;
      }

      const horizontalLength = 20;
      let labelX = bendPoint[0] + horizontalLength * horizontalDirection;
      let labelY = bendPoint[1];

      // 界壁检测（同上）
      const padding = 10;
      const labelWidth = d.data.label.length * 7;
      if (labelX + labelWidth / 2 > width / 2 - padding) {
        labelX = width / 2 - padding - labelWidth / 2;
      } else if (labelX - labelWidth / 2 < -width / 2 + padding) {
        labelX = -width / 2 + padding + labelWidth / 2;
      }
      if (labelY > height / 2 - padding) {
        labelY = height / 2 - padding;
      }

      return `translate(${labelX},${labelY})`;
    })
    .attr("text-anchor", (d: any) => {
      const centroid = arc.centroid(d);
      const midAngle = Math.atan2(centroid[1], centroid[0]);
      // 修正文本对齐方式
      return midAngle > Math.PI / 2 || midAngle < -Math.PI / 2 ? "end" : "start";
    })
    .text((d: any) => d.data.label);
};
</script>

<style scoped>
.doughnut-chart-container {
  width: 100%;
  height: 100%;
}
</style>
